package com.qh.redis.service;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.qh.common.config.Constant;
import com.qh.common.config.SpringUtil;
import com.qh.common.utils.R;
import com.qh.pay.api.PayApi;
import com.qh.pay.api.constenum.*;
import com.qh.pay.api.utils.*;
import com.qh.pay.dao.PayQrConfigDao;
import com.qh.pay.domain.*;
import com.qh.pay.exrick.common.utils.StringUtils;
import com.qh.pay.service.MerchantService;
import com.qh.pay.service.PayQrConfigService;
import com.qh.pay.service.PayQrService;
import com.qh.pay.service.PayService;
import com.qh.pay.service.impl.PayQrServiceImpl;
import com.qh.pay.service.impl.PayServiceImpl;
import com.qh.query.service.OrderQueryService;
import org.apache.http.client.fluent.Request;
import org.redisson.api.RLock;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.core.RedisTemplate;

import com.qh.common.config.CfgKeyConst;
import com.qh.pay.api.Order;
import com.qh.redis.RedisConstants;
import com.qh.redis.constenum.ConfigParent;
import com.qh.system.domain.ConfigDO;

import javax.annotation.Resource;

/**
 * @ClassName: RedisUtil
 * @Description: redis用到的常用操作
 * @date 2017年10月27日 上午10:26:01
 */
public class RedisUtil {
//
//      @Autowired
//    private PayQrServiceImpl payQrService = new PayQrServiceImpl();
//
private static MerchantService merchantService = SpringUtil.getBean(MerchantService.class);

    private static PayQrService payQrService = SpringUtil.getBean(PayQrService.class);
    private static PayQrConfigDao payQrConfigDao = SpringUtil.getBean(PayQrConfigDao.class);
    private static OrderQueryService orderQueryService = SpringUtil.getBean(OrderQueryService.class);

    private static PayQrConfigService payQrConfigService = SpringUtil.getBean(PayQrConfigService.class);
    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(RedisUtil.class);
    private static RedisTemplate<String, Object> redisTemplate;
    private static RedisTemplate<String, Object> redisNotifyTemplate;

    public static void setValue(String key, Object obj) {
        redisTemplate.opsForValue().set(key, obj);
    }

    public static Object getValue(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    public static Object getHashValue(String key, Object obj) {
        return redisTemplate.opsForHash().get(key, obj);
    }

    public static List<Object> getHashValueList(String key) {

        return redisTemplate.opsForHash().values(key);
    }

    public static int getHashValueCount(String key) {
        return redisTemplate.opsForHash().size(key).intValue();
    }

    public static List<Object> getHashValueListForStringObjBlur(String key, String patten) {
        Set<Object> keySet = redisTemplate.opsForHash().keys(key);

        List<Object> keyList = new ArrayList<>();
        for (Object obj : keySet) {
            String tmpKey = obj.toString();
            if (tmpKey.matches(".*" + patten + ".*")) {
                keyList.add(tmpKey);
            }
        }
        return redisTemplate.opsForHash().multiGet(key, keyList);
    }

    /**
     * @Description 设置聚富支付网管最近连接时间
     */
    public static void setQrGatewayLastSyncTime(String merchNo, String outChannel, String accountNo, Object obj) {
        redisTemplate.opsForHash().put(RedisConstants.cache_qr_last_login_time,
                merchNo + RedisConstants.link_symbol + outChannel + RedisConstants.link_symbol + accountNo, obj);
    }

    /**
     * @Description 获取聚富支付网管最近连接时间
     */
    public static Object getQrGatewayLastSyncTime(String outChannel, String accountNo) {
        return redisTemplate.opsForHash().get(RedisConstants.cache_qr_last_login_time,
                RedisConstants.link_symbol + outChannel + RedisConstants.link_symbol + accountNo);
    }


    /**
     * @param order
     * @Description 支付订单
     */
    public static void setOrder(Order order) {
        redisTemplate.opsForHash().put(RedisConstants.cache_order + order.getMerchNo(), order.getOrderNo(), order);
        redisTemplate.opsForZSet().add(RedisConstants.cache_sort_order + order.getMerchNo(), order.getOrderNo(),
                order.getCrtDate());
    }

    /**
     * @param merchNo
     * @param orderNo
     * @return
     * @Description 获取支付订单
     */
    public static Order getOrder(String merchNo, String orderNo) {
        return (Order) redisTemplate.opsForHash().get(RedisConstants.cache_order + merchNo, orderNo);
    }


    /**
     * @Description 删除支付订单
     */
    public static void removeOrder(String merchNo, String orderNo) {
        redisTemplate.opsForHash().delete(RedisConstants.cache_order + merchNo, orderNo);
        redisTemplate.opsForZSet().remove(RedisConstants.cache_sort_order + merchNo, orderNo);
    }


    /**
     * @param order
     * @Description 代付订单
     */
    public static void setOrderAcp(Order order) {
        redisTemplate.opsForHash().put(RedisConstants.cache_order_acp + order.getMerchNo(), order.getOrderNo(), order);
        redisTemplate.opsForZSet().add(RedisConstants.cache_sort_acp_order + order.getMerchNo(), order.getOrderNo(),
                order.getCrtDate());
    }

    /**
     * @param merchNo
     * @param orderNo
     * @return
     * @Description 获取代付订单
     */
    public static Order getOrderAcp(String merchNo, String orderNo) {
        return (Order) redisTemplate.opsForHash().get(RedisConstants.cache_order_acp + merchNo, orderNo);
    }

    /**
     * @param merchNo
     * @Description 删除代付订单
     */
    public static void removeOrderAcp(String merchNo, String orderNo) {
        redisTemplate.opsForHash().delete(RedisConstants.cache_order_acp + merchNo, orderNo);
        redisTemplate.opsForZSet().remove(RedisConstants.cache_sort_acp_order + merchNo, orderNo);
    }

    /**
     * @param orderKey
     * @param merchNo
     * @param orderNo
     * @return
     * @Description
     */
//    public static boolean setKeyEventExpired(String orderKey, String merchNo, String orderNo) {
//        RLock lock =
//                RedissonLockUtil.getEventLock(orderKey + RedisConstants.link_symbol + merchNo + RedisConstants.link_symbol + orderNo);
//        if (lock.tryLock()) {
//            try {
////                Integer minute = (Integer) redisNotifyTemplate.opsForHash().get(orderKey + merchNo, orderNo);
//
//                Integer minute = 10;
//                logger.info("新的订单过期时间：{}，{}，{}", merchNo, orderNo, minute);
//                if (minute == null) {
//                    minute = RedisConstants.keyevent_10;
//                } else if (minute == 0) {
//                    redisNotifyTemplate.opsForHash().delete(orderKey + merchNo, orderNo);
//                    return false;
//                } else if (minute == RedisConstants.keyevent_160 || minute == RedisConstants.keyevent_320) {
//                    minute = RedisConstants.keyevent_80;
//                }
//                Long timeLive =
//                        redisNotifyTemplate.opsForValue().getOperations().getExpire(orderKey + merchNo + RedisConstants.link_symbol + orderNo);
//                logger.info("新的订单存活时间：{}，{}，{}", merchNo, orderNo, timeLive);
//
//                if (timeLive == null || timeLive < 30) {
//                    redisNotifyTemplate.opsForHash().put(orderKey + merchNo, orderNo,
//                            RedisConstants.evtMinuteMap.get(minute));
//                    redisNotifyTemplate.opsForValue().set(orderKey + merchNo + RedisConstants.link_symbol + orderNo,
//                            minute, minute, TimeUnit.MINUTES);
//                }
//                return true;
//            } finally {
//                lock.unlock();
//            }
//        }
//        return false;
//    }

    /**
     * @param orderKey
     * @param merchNo
     * @param orderNo
     * @return
     * @Description
     */
    public static boolean setKeyEventExpired(String orderKey, String merchNo, String orderNo) {
        RLock lock =
                RedissonLockUtil.getEventLock(orderKey + RedisConstants.link_symbol + merchNo + RedisConstants.link_symbol + orderNo);
        if (lock.tryLock()) {
            try {
//                Integer minute = (Integer) redisNotifyTemplate.opsForHash().get(orderKey + merchNo, orderNo);

                Integer minute = 10;
                logger.info("新的订单过期时间：{}，{}，{}", merchNo, orderNo, minute);
                if (minute == null) {
                    minute = RedisConstants.keyevent_10;
                } else if (minute == 0) {
                    redisNotifyTemplate.opsForHash().delete(orderKey + merchNo, orderNo);
                    return false;
                } else if (minute == RedisConstants.keyevent_160 || minute == RedisConstants.keyevent_320) {
                    minute = RedisConstants.keyevent_80;
                }
                Long timeLive =
                        redisNotifyTemplate.opsForValue().getOperations().getExpire(orderKey + merchNo + RedisConstants.link_symbol + orderNo);
                logger.info("新的订单存活时间：{}，{}，{}", merchNo, orderNo, timeLive);

                if (timeLive == null || timeLive < 30) {
                    redisNotifyTemplate.opsForHash().put(orderKey + merchNo, orderNo,
                            RedisConstants.evtMinuteMap.get(minute));
                    redisNotifyTemplate.opsForValue().set(orderKey + merchNo + RedisConstants.link_symbol + orderNo,
                            minute, minute, TimeUnit.MINUTES);
                }
                return true;
            } finally {
                lock.unlock();
            }
        }
        return false;
    }





    /**
     * @Description 支付订单
     */
    public static void setOrderKeyEventExpired(String merchNo, String orderNo,int num) {
        redisTemplate.opsForHash().put(RedisConstants.cache_keyevent_ord,merchNo+orderNo, num);

    }




    /**
     * @Description 删除回调通知
     */
    public static void removeOrderKeyEventExpired(String merchNo, String orderNo) {
        redisTemplate.opsForHash().delete(RedisConstants.cache_keyevent_ord,
                 merchNo+orderNo);
   }
    /**
     * @return
     * @Description 未通知订单重新通知
     */
    @SuppressWarnings("unchecked")
    public static  void noticeAll() {

        Map<Object, Object> hashMap =
                redisTemplate.opsForHash().entries(RedisConstants.cache_keyevent_ord );
        for (Map.Entry<Object, Object> entry : hashMap.entrySet()) {
            String []mapKey = ((String) entry.getKey()).split(",");
            String merchNo = mapKey[0];
            String orderNo = mapKey[1];
            int num = (int) entry.getValue();

            if (num < 20) {
                //执行通知
                Order order =orderQueryService.get(orderNo,merchNo);
                if (order == null) {
                    return ;
                }
                if (OrderState.succ.id() == order.getOrderState()) {

                    String stateDesc = OrderState.desc().get(order.getOrderState());
                    String result = null;
                    logger.info("重复回调通知请求：{},{},{},{}，{}", order.getNotifyUrl(), order.getMerchNo(), order.getOrderNo(),
                            stateDesc,num);
                        Map<String, String> data = PayService.initRspData(order);
                        data.put(OrderParamKey.orderState.name(), String.valueOf(order.getOrderState()));
                        data.put(OrderParamKey.merchNo.name(), order.getMerchNo());
                        data.put(OrderParamKey.amount.name(), order.getAmount().toString());
                        data.put(OrderParamKey.orderNo.name(), order.getOrderNo());
                        result = RequestUtils.doPostJson(order.getNotifyUrl(),
                             decryptAndSignMD5(data, order.getMsg()).jsonStr());
                        logger.info("{}重发状态返回结果：{},{},{}", stateDesc, order.getMerchNo(), order.getOrderNo(), result);
                        // todo 通知商户返回
                        if (result.contains("ok") || result.contains("success")) {
                            removeOrderKeyEventExpired(merchNo,orderNo);
                            continue;
                        }
                        setOrderKeyEventExpired(merchNo,orderNo,num+1);

                }

            }else{
                removeOrderKeyEventExpired(merchNo,orderNo);
            }
        }

    }

    /**
     * @param data
     * @return
     * @Description 公钥加密，私钥签名
     */
    public static R decryptAndSignMD5(Map<String, ?> data, String msg) {
        try {
            logger.info("回调商户 返回明文数据:" + JSON.toJSONString(data));
//            byte[]    context = JSON.toJSONString(data).getBytes("UTF-8");
            Base64.Encoder encoder = Base64.getEncoder();
            //编码
            String encodedText = encoder.encodeToString(JSON.toJSONString(data).getBytes("UTF-8"));
            String merchNo = data.get("merchNo").toString();
            R r = R.ok();

            String privateKey = merchantService.getPrivateKey(merchNo);
            String sign = Md5Util.sign(encodedText, privateKey, "UTF-8");
            r.put("sign", sign).put("context", encodedText);
            r.put(Constant.result_msg, msg).put("merchNo", merchNo).put(OrderParamKey.encryptType.name(), "MD5");
            logger.info("回调商户 返回加密数据:" + JSON.toJSONString(r));
            return r;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("返回数据签名 失败！");
        }
        return R.error("返回数据签名失败！");
    }
    /**
     * @param orderKey
     * @param merchNo
     * @param orderNo
     * @return
     * @Description
     */
    public static void delKeyEventExpired(String orderKey, String merchNo, String orderNo) {
        redisNotifyTemplate.opsForHash().delete(orderKey + merchNo, orderNo);
    }

    /**
     * @param merchNo
     * @Description 获取商户余额
     */
    public static PayAcctBal getMerchBal(String merchNo) {
        return (PayAcctBal) redisTemplate.opsForHash().get(RedisConstants.cache_bal_merch, merchNo);
    }

    public static void setMerchBal(PayAcctBal payAcctBal) {
        redisTemplate.opsForHash().put(RedisConstants.cache_bal_merch, payAcctBal.getUsername(), payAcctBal);
    }

    /**
     * @Description 获取支付通道余额
     */
    public static PayAcctBal getPayMerchBal(String payCompany, String payMerch, String outChannel) {
        PayAcctBal payAcctBal = (PayAcctBal) redisTemplate.opsForHash().get(RedisConstants.cache_bal_payMerch,
                payCompany + RedisConstants.link_symbol + payMerch);
        if (payAcctBal == null) {
            payAcctBal = createPayAcctBal(payMerch);
        }
        return payAcctBal;
    }

    /**
     * @param payMerch
     * @Description 获取支付通道余额
     */
    public static PayAcctBal getPayMerchBal(String payCompany, String payMerch) {
        PayAcctBal payAcctBal = (PayAcctBal) redisTemplate.opsForHash().get(RedisConstants.cache_bal_payMerch,
                payCompany + RedisConstants.link_symbol + payMerch);
        if (payAcctBal == null) {
            payAcctBal = createPayAcctBal(payMerch);
        }
        return payAcctBal;
    }

    public static void setPayMerchBal(PayAcctBal payAcctBal, String payCompany, String payMerch) {
        redisTemplate.opsForHash().put(RedisConstants.cache_bal_payMerch,
                payCompany + RedisConstants.link_symbol + payMerch, payAcctBal);
    }

    /**
     * @param payMerch
     * @return
     * @Description 创建支付账户余额
     */
    public static PayAcctBal createPayAcctBal(String payMerch) {
        PayAcctBal payAcctBal = new PayAcctBal();
        payAcctBal.setUserId(0);
        payAcctBal.setUsername(payMerch);
        payAcctBal.setUserType(UserType.payMerch.id());
        payAcctBal.setBalance(BigDecimal.ZERO);
        payAcctBal.setAvailBal(BigDecimal.ZERO);
        return payAcctBal;
    }

    /**
     * @param username
     * @Description 获取代理余额
     */
    public static PayAcctBal getAgentBal(String username) {
        return (PayAcctBal) redisTemplate.opsForHash().get(RedisConstants.cache_bal_agent, username);
    }

    public static void setAgentBal(PayAcctBal payAcctBal) {
        redisTemplate.opsForHash().put(RedisConstants.cache_bal_agent, payAcctBal.getUsername(), payAcctBal);
    }

    /**
     * @param cardType
     * @param payCompany
     * @return
     * @Description 获取银行卡列表
     */
    @SuppressWarnings("unchecked")
    public static List<String> getBanks(Integer cardType, String payCompany) {
        return (List<String>) redisTemplate.opsForHash().get(RedisConstants.cache_banks + cardType, payCompany);
    }

    /**
     * @param cardType
     * @param payCompany
     * @param banks
     * @Description 设置银行卡列表
     */
    public static void setBanks(Integer cardType, String payCompany, List<String> banks) {
        redisTemplate.opsForHash().put(RedisConstants.cache_banks + cardType, payCompany, banks);
    }

    /**
     * @param cardType
     * @param payCompany
     * @return
     * @Description 获取银行卡列表
     */
    @SuppressWarnings("unchecked")
    public static List<String> getBanks(Integer cardType, String payCompany, String payMerch) {
        return (List<String>) redisTemplate.opsForHash().get(RedisConstants.cache_banks + cardType,
                payCompany + RedisConstants.link_symbol + payMerch);
    }

    /**
     * @param cardType
     * @param payCompany
     * @param banks
     * @Description 设置银行卡列表
     */
    public static void setBanks(Integer cardType, String payCompany, String payMerch, List<String> banks) {
        redisTemplate.opsForHash().put(RedisConstants.cache_banks + cardType,
                payCompany + RedisConstants.link_symbol + payMerch, banks);
    }

    /**
     * @param outChannel
     * @Description 支付金额
     */
    public static void setMonAmountOccupy(String outChannel, String accountNo) {
        setMonAmountOccupy(outChannel, accountNo, 5* 60);
    }

    /**
     * @param outChannel
     * @param validTime  有效时间 单位秒
     * @Description 支付订单
     */
    public static void setMonAmountOccupy(String outChannel, String accountNo, int validTime) {
        redisTemplate.opsForHash().put(RedisConstants.cache_monAmount_occupy + RedisConstants.link_symbol + outChannel, accountNo, DateUtil.getCurrentTimeInt() + validTime);
    }

    /***
     *
     * @Description 获取过期时间(剩余时间)
     * @param outChannel
     * @return
     */
    public static int getMonAmountOccupyValidTime(String outChannel, String accountNo) {
        Integer validTime =
                (Integer) redisTemplate.opsForHash().get(RedisConstants.cache_monAmount_occupy + RedisConstants.link_symbol + outChannel
                        , accountNo);
        return validTime == null ? 0 : validTime - DateUtil.getCurrentTimeInt();
    }


    /**
     * @return
     * @Description 释放通道金额
     */
    @SuppressWarnings("unchecked")
    public static  void realseMonAmountOccupyAll(String outChannel) {

        Map<Object, Object> hashMap =
                redisTemplate.opsForHash().entries(RedisConstants.cache_monAmount_occupy + RedisConstants.link_symbol + outChannel);
        for (Map.Entry<Object, Object> entry : hashMap.entrySet()) {
            String mapKey = (String) entry.getKey();
            int mapValue = (int) entry.getValue();
            if (mapValue < DateUtil.getCurrentTimeInt()) {
                paystatus( outChannel,  mapKey,true);


            }
        }

    }


    public static  void paystatus(String outChannel, String accountNo,boolean flag) {

        PayQrConfigDO payQrConfigDO = payQrConfigService.get(outChannel, accountNo);
        if (null != payQrConfigDO) {
            if (pay(payQrConfigDO.getAccountName(), payQrConfigDO.getAccountNo())) {
                payQrConfigDao.updateQrPayState("1",payQrConfigDO.getAccountNo(),payQrConfigDO.getOutChannel());
                String chargeMerchNo = getMonAmountOrderNo(outChannel, accountNo);
                if(!StringUtils.isBlank(chargeMerchNo)){
                    String merchNo = chargeMerchNo.split(RedisConstants.link_symbol)[0];
                    String orderNo = chargeMerchNo.split(RedisConstants.link_symbol)[1];
                    Order order = getOrder(merchNo, orderNo);

                    //直接匹配最近的订单
                    if (order == null) {
                        //支付成功
                        logger.error("该支付订单号不存在,{}", accountNo);
                        payQrService.saveQrOrderLoseData(outChannel, payQrConfigDO.getAccountNo(),
                                String.valueOf(payQrConfigDO.getMoney()),
                                accountNo, "订单丢失", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM" +
                                        "-dd HH:mm:ss")));
                        delMonAmountOccupy(outChannel, accountNo);
                    } else {
                        payQrService.notifyQr(order);
                    }
                }else{
                    //支付成功
                    logger.error("该支付订单号不存在,{}", accountNo);
                    payQrService.saveQrOrderLoseData(outChannel, payQrConfigDO.getAccountNo(),
                            String.valueOf(payQrConfigDO.getMoney()),
                            accountNo, "订单丢失", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM" +
                                    "-dd HH:mm:ss")));
                    delMonAmountOccupy(outChannel, accountNo);
                }

            }else{
                delMonAmountOccupy(outChannel, accountNo);
               if(flag){

                   updateMonAmountNum(payQrConfigDO.getOutChannel(), String.valueOf(payQrConfigDO.getMoney()), true);
               }
            }


        }
    }


    public void paystatus(PayQrConfigDO payQrConfigDO) {
//          PayQrConfigDO payQrConfigDO = payQrConfigService.get(outChannel, accountNo);
        if (null != payQrConfigDO) {
            String outChannel = payQrConfigDO.getOutChannel();
            String accountNo= payQrConfigDO.getAccountNo();
//
                String chargeMerchNo = getMonAmountOrderNo(outChannel, accountNo);
                if(!StringUtils.isBlank(chargeMerchNo)){
                    String merchNo = chargeMerchNo.split(RedisConstants.link_symbol)[0];
                    String orderNo = chargeMerchNo.split(RedisConstants.link_symbol)[1];
                    Order order = getOrder(merchNo, orderNo);

                    //直接匹配最近的订单
                    if (order == null) {
                        //支付成功
                        logger.error("该支付订单号不存在,{}", accountNo);
                        payQrService.saveQrOrderLoseData(outChannel, payQrConfigDO.getAccountNo(),
                                String.valueOf(payQrConfigDO.getMoney()),
                                accountNo, "订单丢失", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM" +
                                        "-dd HH:mm:ss")));
                        delMonAmountOccupy(outChannel, accountNo);
                    } else {
                        payQrService.notifyQr(order);
                    }
                }else{
                    //支付成功
                    logger.error("该支付订单号不存在,{}", accountNo);
                    payQrService.saveQrOrderLoseData(outChannel, payQrConfigDO.getAccountNo(),
                            String.valueOf(payQrConfigDO.getMoney()),
                            accountNo, "订单丢失", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM" +
                                    "-dd HH:mm:ss")));
                    delMonAmountOccupy(outChannel, accountNo);
                }

        }
    }


    private static  boolean pay(String accountName, String accountNo) {

        String resutl = null;
        try {
            resutl = Request.Get("http://api.tbk.dingdanxia.com/shop/order?apikey="+ PayApi.apikey +
                    "&nick=" + accountName + "&order_no=" + accountNo)
                    .execute().returnContent().asString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (ParamUtil.isNotEmpty(resutl)) {
            if (JSONObject.parseObject(resutl).getIntValue("code") == 200) {
                JSONObject jsonObject = JSONObject.parseObject(resutl).getJSONObject("data");
                if ("TRADE_FINISHED".equals(jsonObject.getString("status")) || "SELLER_CONSIGNED_PART".equals(jsonObject.getString(
                        "status")) || "WAIT_SELLER_SEND_GOODS".equals(jsonObject.getString("status"))
                        || "WAIT_BUYER_CONFIRM_GOODS".equals(jsonObject.getString("status"))) {
                    payQrConfigService.updatePayState("1",accountNo,OutChannel.ali.name());
                    return true;
                }
            }
        }

        return false;
    }

    /***
     *
     * @Description 判断订单是否占用
     * @param outChannel
     * @return
     */
    public static boolean ifMonAmountOccupy(String outChannel, String accountNo) {
        Integer validTime =
                (Integer) redisTemplate.opsForHash().get(RedisConstants.cache_monAmount_occupy + RedisConstants.link_symbol + outChannel, accountNo);

        return validTime != null && (validTime - DateUtil.getCurrentTimeInt()) > 0;
    }

    /**
     * @param outChannel
     * @Description 支付订单
     */
    public static void delMonAmountOccupy(String outChannel, String accountNo) {
        redisTemplate.opsForHash().delete(RedisConstants.cache_monAmount_occupy + RedisConstants.link_symbol + outChannel, accountNo);
    }

    /**
     * @param outChannel
     * @param orderNo
     * @Description 设置支付金额订单号
     */
    public static void setMonAmountOrderNo(String outChannel, String accountNo,
                                           String orderNo) {
        redisTemplate.opsForHash().put(RedisConstants.cache_monAmount_orderNo + RedisConstants.link_symbol + outChannel, accountNo, orderNo);

    }

    /**
     * @param outChannel
     * @return
     * @Description 获取支付金额订单号
     */
    public static String getMonAmountOrderNo(String outChannel, String accountNo) {
        return (String) redisTemplate.opsForHash().get(RedisConstants.cache_monAmount_orderNo + RedisConstants.link_symbol + outChannel,
                accountNo);
    }

    /**
     * @param outChannel
     * @param monAmount
     * @param num
     * @Description 设置通道数量
     */
    public static void setMonAmountNum(String outChannel, String monAmount,
                                       int num) {
        redisTemplate.opsForHash().put(RedisConstants.monAmount_num + RedisConstants.link_symbol + outChannel,
                monAmount, num);

    }

    /**
     * @param outChannel
     * @param monAmount
     * @Description 获取通道金额数量
     */
    public static int getMonAmountNum(String outChannel, String monAmount
    ) {
        Integer i =
                (Integer) redisTemplate.opsForHash().get(RedisConstants.monAmount_num + RedisConstants.link_symbol + outChannel
                        , monAmount);
        if (i == null) {
            return 0;
        } else {
            return i;
        }
    }

    public static void updateMonAmountNum(String outChannel, String monAmount, boolean flag) {
        monAmount = ParamUtil.subZeroAndDot(monAmount);
        int num = RedisUtil.getMonAmountNum(outChannel, monAmount);
        if (flag) {
            num++;
        } else {
            num--;
        }
        RedisUtil.setMonAmountNum(outChannel, monAmount, num);
    }

    /**
     * @param outChannel
     * @Description 删除通道金额数量
     */
    public static void initMonAmountNum(String outChannel) {

        Map<Object, Object> hashMap =
                redisTemplate.opsForHash().entries(RedisConstants.monAmount_num + RedisConstants.link_symbol + outChannel);
        for (Map.Entry<Object, Object> entry : hashMap.entrySet()) {
            String mapKey = (String) entry.getKey();
            redisTemplate.opsForHash().delete(RedisConstants.monAmount_num + RedisConstants.link_symbol + outChannel,
                    mapKey);
        }
        HashMap<String, Object> hashMaps = new HashMap<>();
        hashMaps.put("outChannel", outChannel);
        hashMaps.put("useStatus", 1);
        hashMaps.put("payStatus","0");
        List<PayQrConfigDO> payQrConfigDOS = payQrConfigService.list(hashMaps);
        for (PayQrConfigDO payQrConfigDO : payQrConfigDOS) {
            updateMonAmountNum(payQrConfigDO.getOutChannel(), String.valueOf(payQrConfigDO.getMoney()), true);
        }



    }

    /**
     * @return
     * @Description 获取通道金额
     */
    @SuppressWarnings("unchecked")
    public static List<String> getMonAmount(String outChannel) {
        ArrayList<String> list = new ArrayList<>();
        Map<Object, Object> hashMap =
                redisTemplate.opsForHash().entries(RedisConstants.monAmount_num + RedisConstants.link_symbol + outChannel);
        for (Map.Entry<Object, Object> entry : hashMap.entrySet()) {
            String mapKey = (String) entry.getKey();
            int mapValue = (int) entry.getValue();
            if (mapValue > 0) {
                list.add(mapKey);
            }
        }
        return list;
    }

    /**
     * @return
     * @Description 获取通道金额
     */
    @SuppressWarnings("unchecked")
    public static List<MoneyNum> getMonAmountNum(String outChannel) {
        List<MoneyNum> list = new ArrayList<>();
        Map<Object, Object> hashMap =
                redisTemplate.opsForHash().entries(RedisConstants.monAmount_num + RedisConstants.link_symbol + outChannel);
        for (Map.Entry<Object, Object> entry : hashMap.entrySet()) {
            String mapKey = (String) entry.getKey();
            int mapValue = (int) entry.getValue();
            if (mapValue > 0) {
                MoneyNum data = new MoneyNum();
                data.setOutChannel(outChannel);
                data.setMoney(mapKey);
                data.setNum(mapValue + "");
                list.add(data);
            }
        }
        return list;
    }


    /**
     * @param outChannel
     * @param accountNo
     * @Description 删除支付金额订单号
     */
    public static void delMonAmountOrderNo(String outChannel, String accountNo) {
        redisTemplate.opsForHash().delete(RedisConstants.cache_monAmount_orderNo + RedisConstants.link_symbol + outChannel, accountNo);


    }

    /**
     * @param outChannel
     * @param businessNo
     * @Description 支付金额业务单号
     */
    public static void setQrBusinessNo(String outChannel, String accountNo, String businessNo) {
        redisTemplate.opsForHash().put(RedisConstants.cache_qr_businessNo + RedisConstants.link_symbol + outChannel +
                RedisConstants.link_symbol + accountNo, businessNo, DateUtil.getCurrentTimeInt());
    }

    /**
     * @param outChannel
     * @param businessNo
     * @Description 支付金额业务单号是否存在
     */
    public static boolean ifQrBusinessNo(String outChannel, String accountNo, String businessNo) {
        return redisTemplate.opsForHash().get(RedisConstants.cache_qr_businessNo + RedisConstants.link_symbol + outChannel +
                RedisConstants.link_symbol + accountNo, businessNo) == null;
    }

    /**
     * @param outChannel
     * @param businessNo
     * @Description 删除支付金额业务单号
     */
    public static void delQrBusinessNo(String outChannel, String accountNo, String businessNo) {
        redisTemplate.opsForHash().delete(RedisConstants.cache_qr_businessNo + RedisConstants.link_symbol + outChannel +
                RedisConstants.link_symbol + accountNo, businessNo);
    }

    public static void setMerchCharge(MerchCharge merchCharge) {
        redisTemplate.opsForHash().put(RedisConstants.cache_charge + merchCharge.getMerchNo() +
                RedisConstants.link_symbol + merchCharge.getAccountNo(), merchCharge.getBusinessNo(), merchCharge);
    }

    public static MerchCharge getMerchCharge(String merchNo, String accountNo, String businessNo) {
        return (MerchCharge) redisTemplate.opsForHash().get(RedisConstants.cache_charge + merchNo +
                RedisConstants.link_symbol + accountNo, businessNo);
    }

    public static void delMerchCharge(MerchCharge merchCharge) {
        redisTemplate.opsForHash().delete(RedisConstants.cache_charge + merchCharge.getMerchNo() +
                RedisConstants.link_symbol + merchCharge.getAccountNo(), merchCharge.getBusinessNo());
    }

    /**
     * @param key
     * @return
     * @Description 获取支付参数配置的值
     */
    public static String getPayValue(String key) {
        String value = getPayCommonValue(key);
        if (ParamUtil.isEmpty(value)) {
            value = getPayFilePathValue(key);
        }
        if (ParamUtil.isEmpty(value)) {
            value = getPayIpValue(key);
        }
        return value;
    }

    /**
     * @param payCompany
     * @return
     * @Description 获取改支付公司下的商户号
     */
    public static Set<Object> getMechNoByCompany(String payCompany) {
        return redisTemplate.boundSetOps(RedisConstants.cache_payConfig + PayConfigType.merchantNo.id() + payCompany).members();
    }

    /***
     *
     * @Description 获取资金账户信息
     */
    public static PayAcctBal getPayFoundBal() {
        return (PayAcctBal) redisTemplate.opsForValue().get(RedisConstants.cache_bal_foundAcct);
    }


    public static void setPayFoundBal(PayAcctBal payAcctBal) {
        redisTemplate.opsForValue().set(RedisConstants.cache_bal_foundAcct, payAcctBal);
    }


    public static void syncConfig(ConfigDO config, boolean delateFlag) {
        if (config == null) {
            return;
        }
        if (ParamUtil.isNotEmpty(config.getParentItem())) {
            if (delateFlag) {
                redisTemplate.boundHashOps(RedisConstants.cache_config_parent + config.getParentItem()).delete(config.getConfigItem());
            } else {
                redisTemplate.boundHashOps(RedisConstants.cache_config_parent + config.getParentItem()).put(config.getConfigItem(), config.getConfigValue());
            }
        }
    }

    public static String getConfigValue(String configItem, String parentItem) {
        return (String) redisTemplate.boundHashOps(RedisConstants.cache_config_parent + parentItem).get(configItem);
    }

    public static String getSysConfigValue(String configItem) {
        return (String) redisTemplate.boundHashOps(RedisConstants.cache_config_parent + ConfigParent.sysConfig.name()).get(configItem);
    }

    public static void delConfig(String configItem, String parentItem) {
        if (ParamUtil.isNotEmpty(parentItem)) {
            redisTemplate.boundHashOps(RedisConstants.cache_config_parent + parentItem).delete(configItem);
        }
    }

    public static String getSMSConfigValue(String configItem) {
        return (String) redisTemplate.boundHashOps(RedisConstants.cache_config_parent + ConfigParent.smsConfig.name()).get(configItem);
    }


    /**
     * @param payProperty
     * @Description 同步支付配置信息
     */
    private static boolean flag = false;
    public static void syncPayConfig(PayPropertyDO payProperty) {
        if(!flag){
            flag = true;
          RedisUtil.initMonAmountNum(OutChannel.ali.name());

        }
        if (payProperty != null) {
            Integer configType = payProperty.getConfigType();
            if (configType == null) {
                return;
            }
            String key = payProperty.getConfigKey();
            if (ParamUtil.isNotEmpty(payProperty.getMerchantno())) {
                key = payProperty.getMerchantno() + key;
            }
            String value = payProperty.getValue();
            if (PayConfigType.pass.id() == payProperty.getConfigType()) {
                value = AesUtil.decrypt(value);
                redisTemplate.boundHashOps(RedisConstants.cache_payConfig).put(key, value);
            } else if (PayConfigType.ip.id() == payProperty.getConfigType()) {
                redisTemplate.boundHashOps(RedisConstants.cache_payConfig).delete(key);
                redisTemplate.boundHashOps(RedisConstants.cache_payConfig + PayConfigType.ip.id()).put(key, value);
            } else if (PayConfigType.filePath.id() == payProperty.getConfigType()) {
                redisTemplate.boundHashOps(RedisConstants.cache_payConfig).delete(key);
                redisTemplate.boundHashOps(RedisConstants.cache_payConfig + PayConfigType.filePath.id()).put(key,
                        value);
            } else if (PayConfigType.fileValue.id() == payProperty.getConfigType()) {
                String payFilePath = getSysConfigValue(CfgKeyConst.payFilePath) + value;
                try {
                    redisTemplate.boundHashOps(RedisConstants.cache_payConfig).put(key,
                            ParamUtil.readTxtFileFilter(payFilePath));
                } catch (Exception e) {
                    logger.error("支付配置文件加载失败！{}", payFilePath);
//                    throw new RuntimeException("支付配置文件加载失败" + payFilePath);
                }
            } else if (PayConfigType.merchantNo.id() == payProperty.getConfigType()) {
                redisTemplate.boundHashOps(RedisConstants.cache_payConfig).put(key, value);
                redisTemplate.boundSetOps(RedisConstants.cache_payConfig + PayConfigType.merchantNo.id() + payProperty.getPayCompany()).add(value);
            } else {
                redisTemplate.boundHashOps(RedisConstants.cache_payConfig).put(key, value);
            }
        }

    }

    public static String getPayFilePathValue(String key) {
        String value = getPayValue(key, PayConfigType.filePath);
        if (ParamUtil.isNotEmpty(value)) {
            value = getSysConfigValue(CfgKeyConst.payFilePath) + value;
        }
        return value;
    }

    public static String getPayIpValue(String key) {
        String value = getPayValue(key, PayConfigType.ip);
        if (ParamUtil.isNotEmpty(value)) {
            value = getSysConfigValue(CfgKeyConst.ip) + value;
        }
        return value;
    }

    public static String getPayValue(String key, PayConfigType configType) {
        return (String) redisTemplate.boundHashOps(RedisConstants.cache_payConfig + configType.id()).get(key);
    }

    public static String getPayCommonValue(String key) {
        return (String) redisTemplate.boundHashOps(RedisConstants.cache_payConfig).get(key);
    }

    /**
     * @param payPropertyDO
     * @Description 删除支付配置
     */
    public static void delPayConfig(PayPropertyDO payPropertyDO) {
        if (payPropertyDO != null) {
            delPayConfig(payPropertyDO.getConfigKey(), payPropertyDO);
        }

    }

    /**
     * @param configKey
     * @param payProperty
     * @Description 删除支付配置
     */
    public static void delPayConfig(String configKey, PayPropertyDO payProperty) {
        if (payProperty == null) {
            return;
        }
        if (ParamUtil.isNotEmpty(payProperty.getMerchantno())) {
            configKey = payProperty.getMerchantno() + configKey;
        }
        Integer configType = payProperty.getConfigType();
        if (configType != null) {
            if (PayConfigType.ip.id() == configType) {
                redisTemplate.boundHashOps(RedisConstants.cache_payConfig + PayConfigType.ip.id()).delete(configKey);
            } else if (PayConfigType.filePath.id() == configType) {
                redisTemplate.boundHashOps(RedisConstants.cache_payConfig + PayConfigType.filePath.id()).delete(configKey);
            } else if (PayConfigType.merchantNo.id() == configType) {
                redisTemplate.boundHashOps(RedisConstants.cache_payConfig).delete(configKey);
                redisTemplate.boundSetOps(RedisConstants.cache_payConfig + PayConfigType.merchantNo.id() + payProperty.getPayCompany()).remove(payProperty.getValue());
            } else {
                redisTemplate.boundHashOps(RedisConstants.cache_payConfig).delete(configKey);
            }
        } else {
            redisTemplate.boundHashOps(RedisConstants.cache_payConfig).delete(configKey);
        }
    }

    public static Map<Object, Object> getCacheMap(String key) {
        return redisTemplate.boundHashOps(key).entries();
    }

    public static ConfigDO getCacheConfig(String key) {
        return (ConfigDO) redisTemplate.boundValueOps(RedisConstants.cache_config).
                getOperations().boundValueOps(key).get();
    }

    public static Map<String, Object> getCacheMapDesc(String key) {
        Map<Object, Object> cacheMap = getCacheMap(key);
        Map<String, Object> descMap = new HashMap<String, Object>();
        if (!cacheMap.isEmpty()) {
            ConfigDO configDO = null;
            for (Entry<Object, Object> entry : cacheMap.entrySet()) {
                configDO = getCacheConfig((String) entry.getKey());
                if (configDO != null) {
                    descMap.put((String) entry.getValue(), configDO.getConfigName());
                }
            }
            return descMap;
        } else {
            return descMap;
        }
    }

    public static void setRedisTemplate(RedisTemplate<String, Object> template) {
        redisTemplate = template;
    }

    public static RedisTemplate<String, Object> getRedisTemplate() {
        return redisTemplate;
    }

    public static RedisTemplate<String, Object> getRedisNotifyTemplate() {
        return redisNotifyTemplate;
    }

    public static void setRedisNotifyTemplate(RedisTemplate<String, Object> template) {
        redisNotifyTemplate = template;
    }

    public static void setHashValue(String key, Object key2, Object obj) {
        redisTemplate.opsForHash().put(key, key2, obj);
    }

    public static void setHashValue(String key, Object key2, Object obj, long timeout, TimeUnit unit) {
        redisTemplate.opsForHash().put(key, key2, obj);
        redisTemplate.expire(key, timeout, unit);
    }

    public static String getEmailConfigValue(String configItem) {
        return (String) redisTemplate.boundHashOps(RedisConstants.cache_config_parent + ConfigParent.mailConfig.name()).get(configItem);
    }
}
